/**
* MagicFactory.java 2020/5/15 7:31 下午
* Copyright ©2020 www.bmsoft.com.cn All rights reserved.
* PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package common.factory;

import cluster.AvailableCluster;
import cluster.BroadcastCluster;
import cluster.FailbackCluster;
import cluster.FailfastCluster;
import cluster.FailoverCluster;
import cluster.FailsafeCluster;
import cluster.ForkingCluster;
import common.merger.ArrayMerger;
import common.merger.BooleanArrayMerger;
import common.merger.ByteArrayMerger;
import common.merger.CharArrayMerger;
import common.merger.DoubleArrayMerger;
import common.merger.FloatArrayMerger;
import common.merger.IntArrayMerger;
import common.merger.ListMerger;
import common.merger.LongArrayMerger;
import common.merger.MapMerger;
import common.merger.SetMerger;
import common.merger.ShortArrayMerger;
import common.model.Cluster;
import common.model.Codec2;
import common.model.Merger;
import configcenter.magic.MagicRegistryFactory;
import configcenter.zookeeper.curator.RegistryFactory;
import configcenter.zookeeper.curator.ZookeeperRegistryFactory;
import configcenter.zookeeper.curator.configcenter.DynamicConfigurationFactory;
import configcenter.zookeeper.curator.configcenter.absent.AbsentConfiguratorFactory;
import configcenter.zookeeper.curator.configcenter.nop.NopDynamicConfigurationFactory;
import configcenter.zookeeper.curator.configcenter.override.OverrideConfiguratorFactory;
import configcenter.zookeeper.curator.configcenter.zookeeper.ZookeeperDynamicConfigurationFactory;
import configcenter.zookeeper.curator.integration.ConfiguratorFactory;
import configcenter.zookeeper.curator.integration.RegistryProtocol;
import configcenter.zookeeper.curator.remote.ZookeeperTransporter;
import configcenter.zookeeper.curator.remote.curator.CuratorZookeeperTransporter;
import loadbalancer.LoadBalance;
import loadbalancer.impl.ConsistentHashLoadBalance;
import loadbalancer.impl.LeastActiveLoadBalance;
import loadbalancer.impl.RandomLoadBalance;
import loadbalancer.impl.RoundRobinLoadBalance;
import protocol.Protocol;
import protocol.magic.MagicProtocol;
import proxy.ProxyFactory;
import proxy.javassist.JavassistProxyFactory;
import proxy.jdk.JdkProxyFactory;
import remoting.Transporter;
import remoting.exchange.Exchanger;
import remoting.exchange.support.ExchangeCodec;
import remoting.exchange.support.MagicCountCodec;
import remoting.exchange.support.header.HeaderExchanger;
import remoting.grpc.GrpcTransporter;
import remoting.netty4.NettyTransporter;
import threadpools.ThreadPool;
import threadpools.fixed.FixedThreadPool;

/**
 * File：MagicFactory.java<br>
 * Title: 暂时使用工厂方式，后续再开发更灵活的方式获取各种实现类<br>
 * Description: <br>
 * Company: www.treefinance.com.cn <br>
 * @author heyouchi
 * Date: 2020/5/15
 */
public class MagicFactory implements Factory{

  private static MagicFactory INSTANCE;

  private Transporter transporter;

  private Codec2 codec;

  private ThreadPool threadPool;

  private Exchanger exchanger;

  private RegistryFactory registryFactory;

  private LoadBalance loadBalance;

  private DynamicConfigurationFactory dynamicConfigurationFactory;

  private Cluster cluster;

  private Merger merger;

  private ConfiguratorFactory configuratorFactory;

  private ProxyFactory proxyFactory;

  private ZookeeperTransporter zookeeperTransporter;

  private Protocol remoteProtocol;

  private Object transporterLock = new Object();

  private Object codecLock = new Object();

  private Object threadPoolLock = new Object();

  private Object exchangerLock = new Object();

  private Object registryFactoryLock = new Object();

  private Object loadBalanceLock = new Object();

  private Object dynamicConfigurationFactoryLock = new Object();

  private Object clusterLock = new Object();

  private Object mergerLock = new Object();

  private Object configuratorFactoryLock = new Object();

  private Object proxyFactoryLock = new Object();

  private Object zookeeperTransporterLock = new Object();

  private Object remoteProtocolLock = new Object();

  public static MagicFactory getMagicFactory() {
    if (INSTANCE == null) {
      INSTANCE = new MagicFactory();
    }
    return INSTANCE;
  }

  public Protocol getRemoteProtocol(String name){
    if(name == null) name = "default";
    if(remoteProtocol == null){
      synchronized (remoteProtocolLock){
        if(remoteProtocol == null){
          switch (name){
            case MagicProtocol.NAME:
              remoteProtocol = new MagicProtocol();
            default:
              remoteProtocol = new MagicProtocol();
          }
        }
      }
    }
    return remoteProtocol;
  }

  public Protocol getRemoteProtocol(){
    return getRemoteProtocol(null);
  }

  public ZookeeperTransporter getZookeeperTransporter(String name){
    if(name == null) name = "default";
    if(zookeeperTransporter == null){
      synchronized (zookeeperTransporterLock){
        if(zookeeperTransporter == null){
          switch (name){
            case "curator":
              zookeeperTransporter = new CuratorZookeeperTransporter();
            default:
              zookeeperTransporter = new CuratorZookeeperTransporter();
          }
        }
      }
    }
    return zookeeperTransporter;
  }

  public ZookeeperTransporter getZookeeperTransporter(){
    return getZookeeperTransporter(null);
  }

  public ProxyFactory getProxyFactory(String name){
    if(name == null) name = "default";
    if(proxyFactory == null){
      synchronized (proxyFactoryLock){
        if(proxyFactory == null){
          switch (name){
            case "jdk":
              proxyFactory = new JdkProxyFactory();
            case "javassist":
              proxyFactory = new JavassistProxyFactory();
            default:
              proxyFactory = new JavassistProxyFactory();
          }
        }
      }
    }
    return proxyFactory;
  }

  public ProxyFactory getProxyFactory(){
    return getProxyFactory(null);
  }

  public ConfiguratorFactory getConfiguratorFactory(String name){
    if(name == null) name = "default";
    if(configuratorFactory == null){
      synchronized (configuratorFactoryLock){
        if(configuratorFactory == null){
          switch (name){
            case "override":
              configuratorFactory = new OverrideConfiguratorFactory();
            case "absent":
              configuratorFactory = new AbsentConfiguratorFactory();
            default:
              configuratorFactory = new OverrideConfiguratorFactory();
          }
        }
      }
    }
    return configuratorFactory;
  }

  public ConfiguratorFactory getConfiguratorFactory(){
    return getConfiguratorFactory(null);
  }

  public Merger getMerger(String name){
    if(name == null) name = "default";
    if(merger == null){
      synchronized (mergerLock){
        if(merger == null){
          switch (name){
            case ArrayMerger.NAME:
              merger = new ArrayMerger();
            case BooleanArrayMerger.NAME:
              merger = new BooleanArrayMerger();
            case ByteArrayMerger.NAME:
              merger = new ByteArrayMerger();
            case CharArrayMerger.NAME:
              merger = new CharArrayMerger();
            case DoubleArrayMerger.NAME:
              merger = new DoubleArrayMerger();
            case FailsafeCluster.NAME:
              merger = new FloatArrayMerger();
            case IntArrayMerger.NAME:
              merger = new IntArrayMerger();
            case ListMerger.NAME:
              merger = new ListMerger();
            case LongArrayMerger.NAME:
              merger = new LongArrayMerger();
            case MapMerger.NAME:
              merger = new MapMerger();
            case SetMerger.NAME:
              merger = new SetMerger();
            case ShortArrayMerger.NAME:
              merger = new ShortArrayMerger();
            default:
              merger = new ArrayMerger();
          }
        }
      }
    }
    return merger;
  }

  public Merger getMerger(){
    return getMerger(null);
  }

  public Cluster getCluster(String name){
    if(name == null) name = "default";
    if(cluster == null){
      synchronized (clusterLock){
        if(cluster == null){
          switch (name){
            case AvailableCluster.NAME:
              cluster = new AvailableCluster();
            case BroadcastCluster.NAME:
              cluster = new BroadcastCluster();
            case FailbackCluster.NAME:
              cluster = new FailbackCluster();
            case FailfastCluster.NAME:
              cluster = new FailfastCluster();
            case FailoverCluster.NAME:
              cluster = new FailoverCluster();
            case FailsafeCluster.NAME:
              cluster = new FailsafeCluster();
            case ForkingCluster.NAME:
              cluster = new ForkingCluster();
            default:
              cluster = new FailbackCluster();
          }
        }
      }
    }
    return cluster;
  }

  public Cluster getCluster(){
    return getCluster(null);
  }

  public DynamicConfigurationFactory getDynamicConfigurationFactory(String name){
    if(name == null) name = "default";
    if(dynamicConfigurationFactory == null){
      synchronized (dynamicConfigurationFactoryLock){
        if(dynamicConfigurationFactory == null){
          switch (name){
            case "zk":
              dynamicConfigurationFactory = new ZookeeperDynamicConfigurationFactory();
            case "nop":
              dynamicConfigurationFactory = new NopDynamicConfigurationFactory();
            default:
              dynamicConfigurationFactory = new NopDynamicConfigurationFactory();
          }
        }
      }
    }
    return dynamicConfigurationFactory;
  }

  public DynamicConfigurationFactory getDynamicConfigurationFactory(){
    return getDynamicConfigurationFactory(null);
  }

  public Transporter getTransporter(String name){
    if(name == null) name = "default";
    if(transporter == null){
      synchronized (transporterLock){
        if(transporter == null){
          switch (name){
            case "netty":
              transporter = new NettyTransporter();
            case "grpc":
              transporter = new GrpcTransporter();
            default:
              transporter = new NettyTransporter();
          }
        }
      }
    }
    return transporter;
  }

  public Transporter getTransporter(){
    return getTransporter(null);
  }

  public Codec2 getCodec2(String name){
    if(name == null) name = "default";
    if(codec == null){
      synchronized (codecLock){
        if(codec == null){
          switch (name){
            case "hessian":
              codec = new MagicCountCodec();
            default:
              codec = new MagicCountCodec();
          }
        }
      }
    }
    return codec;
  }

  public Codec2 getCodec2(){
    return getCodec2(null);
  }

  public ThreadPool getThreadPool(String name){
    if(name == null) name = "default";
    if(threadPool == null){
      synchronized (threadPoolLock){
        if(threadPool == null){
          switch (name){
            case "fixed":
              threadPool = new FixedThreadPool();
            default:
              threadPool = new FixedThreadPool();
          }
        }
      }
    }
    return threadPool;
  }

  public ThreadPool getThreadPool(){
    return getThreadPool(null);
  }

  public Exchanger getExchanger(String name){
    if(name == null) name = "default";
    if(exchanger == null){
      synchronized (exchangerLock){
        if(exchanger == null){
          switch (name){
            case "fixed":
              exchanger = new HeaderExchanger();
            default:
              exchanger = new HeaderExchanger();
          }
        }
      }
    }
    return exchanger;
  }

  public Exchanger getExchanger(){
    return getExchanger(null);
  }

  public RegistryFactory getRegistryFactory(String name){
    if(name == null) name = "default";
    if(registryFactory == null){
      synchronized (registryFactoryLock){
        if(exchanger == null){
          switch (name){
            case "zk":
              registryFactory = new ZookeeperRegistryFactory();
            case "magic":
              registryFactory = new MagicRegistryFactory();
            default:
              registryFactory = new MagicRegistryFactory();
          }
        }
      }
    }
    return registryFactory;
  }

  public RegistryFactory getRegistryFactory(){
    return getRegistryFactory(null);
  }

  public LoadBalance getLoadBalance(String name){
    if(name == null) name = "";
    if(loadBalance == null){
      synchronized (loadBalanceLock){
        if(exchanger == null){
          switch (name){
            case ConsistentHashLoadBalance.NAME:
              loadBalance = new ConsistentHashLoadBalance();
            case LeastActiveLoadBalance.NAME:
              loadBalance = new LeastActiveLoadBalance();
            case RandomLoadBalance.NAME:
              loadBalance = new RandomLoadBalance();
            case RoundRobinLoadBalance.NAME:
              loadBalance = new RoundRobinLoadBalance();
            default:
              loadBalance = new RandomLoadBalance();
          }
        }
      }
    }
    return loadBalance;
  }

  public LoadBalance getLoadBalance(){
    return getLoadBalance(null);
  }
}
